#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/module.h>

// 主设备号
#define CHRDEV_MAJOR 200
#define CHRDEV_NAME "chr_dev"

ssize_t chrdev_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
    int ret;
    char *mybuf = "hello world";
    ret = copy_to_user(buf, mybuf, strlen(mybuf));
    if (ret > 0)
    {
        printk("copy to user error\r\n");
        return ret;
    }
    return 0;
}

ssize_t chrdev_write(struct file *filp, const char __user *buf, size_t size, loff_t *pos)
{
    int ret;
    char mybuf[50];
    memset(mybuf, 0, 50);
    ret = copy_from_user(mybuf, buf, size);
    if (ret > 0)
    {
        printk("copy from user error\r\n");
        return ret;
    }
    printk("kernel from user:%s\r\n", mybuf);
    return 0;
}

int chrdev_open(struct inode *inode, struct file *filp)
{
    printk("chrdev is open\r\n");
    return 0;
}

int chrdev_close(struct inode *inode, struct file *filp)
{
    printk("chrdev is close\r\n");
    return 0;
}

// 字符设备操作集
struct file_operations chr_fops = {
    .owner = THIS_MODULE,
    .open = chrdev_open,
    .release = chrdev_close,
    .write = chrdev_write,
    .read = chrdev_read,
};

static int __init chrdev_init(void)
{
    int ret;
    printk("chrdev module init\r\n");
    // 注册设备号
    ret = register_chrdev(CHRDEV_MAJOR, CHRDEV_NAME, &chr_fops);
    if (ret < 0)
    {
        printk("register chrdev error\n");
        return ret;
    }

    return 0;
}

static void __exit chrdev_exit(void)
{
    printk("chrdev module exit\r\n");
    unregister_chrdev(CHRDEV_MAJOR, CHRDEV_NAME);
}

module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_LICENSE("GPL");